home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / lynx-2.4 / WWW / Library / Implementation / HTVMSUtils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-28  |  29.2 KB  |  1,153 lines

  1.  
  2. /* MODULE                            HTVMSUtil.c
  3. **        VMS Utility Routines
  4. **
  5. ** AUTHORS:
  6. **    MD    Mark Donszelmann    duns@vxdeop.cern.ch
  7. **
  8. ** HISTORY:
  9. **    14 Nov 93  MD    Written
  10. **
  11. ** BUGS:
  12. **
  13. **
  14. */
  15.  
  16. #include "HTUtils.h"
  17. #include "tcp.h"
  18. #include "HTFormat.h"
  19. #include "HTStream.h"
  20. #include "HTVMSUtils.h"
  21. /*#include <stdio.h> included by HTUtils.h -- FM */
  22. /*#include <unixlib.h> included by HTUtils.h -- FM */
  23. #include <ssdef.h>
  24. #include <jpidef.h>
  25. #include <prvdef.h>
  26. #include <acldef.h>
  27. #include <chpdef.h>
  28. #include <descrip.h>
  29. #include <lib$routines.h>
  30. #include <starlet.h>
  31. #include <rmsdef.h>
  32.  
  33. #include "LYLeaks.h"
  34.  
  35. #define INFINITY 512                /* File name length @@ FIXME */
  36.  
  37. PUBLIC BOOL HTVMSFileVersions=FALSE; /* Include version numbers in listing? */
  38.  
  39. typedef struct {
  40.    unsigned long BufferLength : 16;
  41.    unsigned long ItemCode : 16;
  42.    unsigned long BufferAddress : 32;
  43.    unsigned long ReturnLengthAddress : 32;
  44. } ItemStruct;
  45.  
  46. extern CONST char * HTHostName NOPARAMS;
  47.  
  48. /* PUBLIC                            HTVMS_authSysPrv()
  49. **        CHECKS IF THIS PROCESS IS AUTHORIZED TO ENABLE SYSPRV
  50. ** ON ENTRY:
  51. **    No arguments.
  52. **
  53. ** ON EXIT:
  54. **    returns    YES if SYSPRV is authorized
  55. */
  56. PUBLIC BOOL HTVMS_authSysPrv NOARGS
  57. {
  58. unsigned long Result;
  59. ItemStruct ItemList[2];
  60. unsigned long Length;
  61. unsigned long Buffer[2];
  62.  
  63.   /* fill Item */
  64.   ItemList[0].BufferLength = sizeof(Buffer);
  65.   ItemList[0].BufferAddress = (unsigned long)Buffer;
  66.   ItemList[0].ReturnLengthAddress = (unsigned long)&Length;
  67.   ItemList[0].ItemCode = JPI$_AUTHPRIV;
  68.  
  69.   /* terminate list */
  70.   ItemList[1].ItemCode = 0;
  71.   ItemList[1].BufferLength = 0;
  72.  
  73.   /* call system */
  74.   Result = sys$getjpiw(0, 0, 0, ItemList, 0, 0, 0);
  75.  
  76.   if (Result != SS$_NORMAL)
  77.      return(NO);  
  78.  
  79.   if (Buffer[0] & PRV$M_SYSPRV)
  80.      return(YES);
  81.  
  82.   return(NO);  
  83. }
  84.  
  85.  
  86.  
  87. /* PUBLIC                            HTVMS_enableSysPrv()
  88. **        ENABLES SYSPRV
  89. ** ON ENTRY:
  90. **    No arguments.
  91. **
  92. ** ON EXIT:
  93. **    
  94. */
  95. PUBLIC void HTVMS_enableSysPrv NOARGS
  96. {
  97. unsigned long Result;
  98. unsigned long Prv[2], PreviousPrv[2];
  99.  
  100.    Prv[0] = PRV$M_SYSPRV;
  101.    Prv[1] = 0;
  102.    Result = sys$setprv(1,&Prv,0,&PreviousPrv);
  103.  
  104.    if (TRACE) {
  105.       if (Result == SS$_NORMAL) {
  106.          if (!(PreviousPrv[0] & PRV$M_SYSPRV)) {
  107.             fprintf(stderr, "HTVMS_enableSysPrv: Enabled SYSPRV\n");
  108.          }
  109.       }
  110.    }
  111. }
  112.  
  113.  
  114.  
  115. /* PUBLIC                            HTVMS_disableSysPrv()
  116. **        DISABLES SYSPRV
  117. ** ON ENTRY:
  118. **    No arguments.
  119. **
  120. ** ON EXIT:
  121. **    
  122. */
  123. PUBLIC void HTVMS_disableSysPrv NOARGS
  124. {
  125. unsigned long Result;
  126. unsigned long Prv[2], PreviousPrv[2];
  127.  
  128.    Prv[0] = PRV$M_SYSPRV;
  129.    Prv[1] = 0;
  130.    Result = sys$setprv(0,&Prv,0,&PreviousPrv);
  131.  
  132.    if (TRACE) {
  133.       if (Result == SS$_NORMAL) {
  134.          if (PreviousPrv[0] & PRV$M_SYSPRV) {
  135.             fprintf(stderr, "HTVMS_disableSysPrv: Disabled SYSPRV\n");
  136.          }
  137.       }
  138.    }
  139. }
  140.  
  141.  
  142.  
  143. /* PUBLIC                            HTVMS_checkAccess()
  144. **        CHECKS ACCESS TO FILE FOR CERTAIN USER
  145. ** ON ENTRY:
  146. **    FileName    The file to be accessed
  147. **    UserName    Name of the user to check access for.
  148. **            User nobody, represented by "" is given NO for an answer
  149. **    Method        Name of the method to be chceked
  150. **
  151. ** ON EXIT:
  152. **    returns YES if access is allowed
  153. **    
  154. */
  155. PUBLIC BOOL HTVMS_checkAccess ARGS3(
  156.     CONST char *, FileName,
  157.     CONST char *, UserName,
  158.     CONST char *, Method)
  159. {
  160. unsigned long Result;
  161. ItemStruct ItemList[2];
  162. unsigned long Length;
  163. unsigned long Buffer;
  164. unsigned long ObjType;
  165.  
  166. char *VmsName;
  167.  
  168. struct dsc$descriptor_s FileNameDesc;
  169. struct dsc$descriptor_s UserNameDesc;
  170.  
  171. char *colon;
  172.  
  173.    /* user nobody should access as from account under which server is running */
  174.    if (0 == strcmp(UserName,""))
  175.       return(NO);
  176.  
  177.    /* check Filename and convert */
  178.    colon = strchr(FileName,':');
  179.    if (colon)
  180.       VmsName = HTVMS_name("",colon+1);
  181.    else
  182.       VmsName = HTVMS_name("",FileName);
  183.  
  184.    /* check for GET */
  185.    if (0 == strcmp(Method,"GET"))
  186.    {
  187.      /* fill Item */
  188.      ItemList[0].BufferLength = sizeof(Buffer);
  189.      ItemList[0].BufferAddress = (unsigned long)&Buffer;
  190.      ItemList[0].ReturnLengthAddress = (unsigned long)&Length;
  191.      ItemList[0].ItemCode = CHP$_FLAGS;
  192.  
  193.      /* terminate list */
  194.      ItemList[1].ItemCode = 0;
  195.      ItemList[1].BufferLength = 0;
  196.  
  197.      /* fill input */
  198.      ObjType = ACL$C_FILE;
  199.      Buffer = CHP$M_READ;
  200.      UserNameDesc.dsc$w_length = strlen(UserName);
  201.      UserNameDesc.dsc$b_dtype = DSC$K_DTYPE_T;
  202.      UserNameDesc.dsc$b_class = DSC$K_CLASS_S;
  203.      UserNameDesc.dsc$a_pointer = (char *)UserName;
  204.      FileNameDesc.dsc$w_length = strlen(VmsName);
  205.      FileNameDesc.dsc$b_dtype = DSC$K_DTYPE_T;
  206.      FileNameDesc.dsc$b_class = DSC$K_CLASS_S;
  207.      FileNameDesc.dsc$a_pointer = VmsName;
  208.  
  209.      /* call system */
  210.      Result = sys$check_access(&ObjType,&FileNameDesc,&UserNameDesc,ItemList);
  211.  
  212.      if (Result == SS$_NORMAL)
  213.         return(YES);
  214.      else
  215.         return(NO);
  216.    }
  217.  
  218.    return(NO);
  219. }
  220.  
  221.  
  222.  
  223. /* PUBLIC                            HTVMS_wwwName()
  224. **        CONVERTS VMS Name into WWW Name 
  225. ** ON ENTRY:
  226. **    vmsname        VMS file specification (NO NODE)
  227. **
  228. ** ON EXIT:
  229. **    returns     www file specification
  230. **
  231. ** EXAMPLES:
  232. **    vmsname                wwwname
  233. **    DISK$USER             disk$user
  234. **    DISK$USER:             /disk$user/
  235. **    DISK$USER:[DUNS]         /disk$user/duns
  236. **    DISK$USER:[DUNS.ECHO]         /disk$user/duns/echo
  237. **    [DUNS]                 duns
  238. **    [DUNS.ECHO]             duns/echo
  239. **    [DUNS.ECHO.-.TRANS]         duns/echo/../trans
  240. **    [DUNS.ECHO.--.TRANS]         duns/echo/../../trans
  241. **    [.DUNS]             duns
  242. **    [.DUNS.ECHO]             duns/echo
  243. **    [.DUNS.ECHO]TEST.COM         duns/echo/test.com 
  244. **    TEST.COM             test.com
  245. **
  246. **    
  247. */
  248. PUBLIC char * HTVMS_wwwName ARGS1(
  249.     char *, vmsname)
  250. {
  251. static char wwwname[256];
  252. char *src, *dst;
  253. int dir;
  254.    dst = wwwname;
  255.    src = vmsname;
  256.    dir = 0;
  257.    if (strchr(src,':')) *(dst++) = '/';
  258.    for ( ; *src != '\0' ; src++)
  259.    {
  260.       switch(*src)
  261.       {
  262.          case ':':  *(dst++) = '/'; break;
  263.          case '-': if (dir)
  264.             {
  265.                if ((*(src-1)=='[' || *(src-1)=='.' || *(src-1)=='-') && 
  266.                   (*(src+1)=='.' || *(src+1)=='-'))
  267.               {
  268.                   *(dst++) = '/';
  269.                           *(dst++) = '.'; 
  270.                           *(dst++) = '.';
  271.               }
  272.               else
  273.                   *(dst++) = '-';
  274.            }
  275.            else
  276.            {
  277.               if (*(src-1) == ']') *(dst++) = '/';
  278.               *(dst++) = '-';
  279.            }
  280.                    break;
  281.          case '.': if (dir)
  282.                    {
  283.                       if (*(src-1) != '[') *(dst++) = '/';
  284.                    }
  285.                    else
  286.            {
  287.               if (*(src-1) == ']') *(dst++) = '/';
  288.                       *(dst++) = '.';
  289.            }
  290.                    break;
  291.          case '[': dir = 1; break;
  292.          case ']': dir = 0; break;
  293.          default:  if (*(src-1) == ']') *(dst++) = '/';
  294.                    *(dst++) = *src; 
  295.                    break;
  296.       }
  297.    }
  298.    *(dst++) = '\0';
  299.    return(wwwname);
  300. }
  301.  
  302.  
  303. /* PUBLIC                            HTVMS_name()
  304. **        CONVERTS WWW name into a VMS name
  305. ** ON ENTRY:
  306. **    nn        Node Name (optional)
  307. **    fn        WWW file name
  308. **
  309. ** ON EXIT:
  310. **    returns     vms file specification
  311. **
  312. ** Bug:    Returns pointer to static -- non-reentrant
  313. */
  314. PUBLIC char * HTVMS_name ARGS2(
  315.     CONST char *, nn, 
  316.     CONST char *, fn)
  317. {
  318.  
  319. /*    We try converting the filename into Files-11 syntax. That is, we assume
  320. **    first that the file is, like us, on a VMS node. We try remote
  321. **    (or local) DECnet access. Files-11, VMS, VAX and DECnet
  322. **    are trademarks of Digital Equipment Corporation. 
  323. **    The node is assumed to be local if the hostname WITHOUT DOMAIN
  324. **    matches the local one. @@@
  325. */
  326.     static char vmsname[INFINITY];    /* returned */
  327.     char * filename = (char*)malloc(strlen(fn)+1);
  328.     char * nodename = (char*)malloc(strlen(nn)+2+1);    /* Copies to hack */
  329.     char *second;        /* 2nd slash */
  330.     char *last;            /* last slash */
  331.     
  332.     char * hostname = (char *)HTHostName();
  333.  
  334.     if (!filename || !nodename) outofmem(__FILE__, "HTVMSname");
  335.     strcpy(filename, fn);
  336.     strcpy(nodename, "");    /* On same node? Yes if node names match */
  337.     if (strncmp(nn,"localhost",9)) {
  338.         char *p, *q;
  339.         for (p=hostname, q=(char *)nn;
  340.          *p && *p!='.' && *q && *q!='.'; p++, q++){
  341.         if (TOUPPER(*p)!=TOUPPER(*q)) {
  342.             strcpy(nodename, nn);
  343.         q = strchr(nodename, '.');    /* Mismatch */
  344.         if (q) *q=0;            /* Chop domain */
  345.         strcat(nodename, "::");        /* Try decnet anyway */
  346.         break;
  347.         }
  348.     }
  349.     }
  350.  
  351.     second = strchr(filename+1, '/');        /* 2nd slash */
  352.     last = strrchr(filename, '/');    /* last slash */
  353.         
  354.     if (!second) {                /* Only one slash */
  355.     sprintf(vmsname, "%s%s", nodename, filename + 1);
  356.     } else if(second==last) {        /* Exactly two slashes */
  357.     *second = 0;        /* Split filename from disk */
  358.     sprintf(vmsname, "%s%s:%s", nodename, filename+1, second+1);
  359.     *second = '/';    /* restore */
  360.     } else {                 /* More than two slashes */
  361.     char * p;
  362.     *second = 0;        /* Split disk from directories */
  363.     *last = 0;        /* Split dir from filename */
  364.     sprintf(vmsname, "%s%s:[%s]%s",
  365.         nodename, filename+1, second+1, last+1);
  366.     *second = *last = '/';    /* restore filename */
  367.     for (p=strchr(vmsname, '['); *p!=']'; p++)
  368.         if (*p=='/') *p='.';    /* Convert dir sep.  to dots */
  369.     }
  370.     free(nodename);
  371.     free(filename);
  372.     return vmsname;
  373. }
  374.  
  375. /*
  376. **    The code below is for directory browsing by VMS Curses clients.
  377. **    It is based on the newer WWWLib's HTDirBrw.c. - Foteos Macrides
  378. */
  379. PUBLIC int HTStat ARGS2(
  380.     CONST char *, filename, 
  381.     stat_t *, info)
  382. {
  383.    /* 
  384.       the following stuff does not work in VMS with a normal stat...
  385.       -->   /disk$user/duns/www if www is a directory
  386.         is statted like:     /disk$user/duns/www.dir 
  387.         after a normal stat has failed
  388.       -->   /disk$user/duns    if duns is a toplevel directory
  389.         is statted like:    /disk$user/000000/duns.dir
  390.       -->   /disk$user since disk$user is a device
  391.         is statted like:    /disk$user/000000/000000.dir
  392.       -->   /            
  393.         searches all devices, no solution yet...
  394.       -->   /vxcern!/disk$cr/wwwteam/login.com
  395.         is not statted but granted with fake information...
  396.    */
  397. int Result;
  398. int Len;
  399. char *Ptr, *Ptr2;
  400. char Name[256];
  401.  
  402.    /* try normal stat... */
  403.    Result = stat((char *)filename,info);
  404.    if (Result == 0)
  405.       return(Result);
  406.  
  407.    /* make local copy */
  408.    strcpy(Name,filename);
  409.  
  410. #ifdef NOT_USED
  411.    /* if filename contains a node specification (! or ::), we will try to access
  412.       the file via DECNET, but we do not stat it..., just return success 
  413.       with some fake information... */
  414.    if (HTVMS_checkDecnet(Name))
  415.    {
  416.       /* set up fake info, only the one we use... */
  417.       info->st_dev = NULL;
  418.       info->st_ino[0] = 0;
  419.       info->st_ino[1] = 0;
  420.       info->st_ino[2] = 0;
  421.       info->st_mode = S_IFREG | S_IREAD;    /* assume it is a regular Readable file */
  422.       info->st_nlink = NULL;
  423.       info->st_uid = 0;
  424.       info->st_gid = 0;
  425.       info->st_rdev = 0;
  426.       info->st_size = 0;
  427.       info->st_atime = time(NULL);
  428.       info->st_mtime = time(NULL);
  429.       info->st_ctime = time(NULL);
  430.  
  431.       return(0);
  432.    }
  433. #endif /* NOT_USED */
  434.  
  435.    /* failed,so do device search in case root is requested */
  436.    if (!strcmp(Name,"/"))
  437.    {  /* root requested */
  438.       return(-1);
  439.    }
  440.    
  441.    /* failed so this might be a directory, add '.dir' */
  442.    Len = strlen(Name);
  443.    if (Name[Len-1] == '/')
  444.       Name[Len-1] = '\0';
  445.    
  446.    /* fail in case of device */
  447.    Ptr = strchr(Name+1,'/');
  448.    if ((Ptr == NULL) && (Name[0] == '/'))
  449.    {  /* device only... */
  450.       strcat(Name,"/000000/000000");
  451.    }
  452.    
  453.    if (Ptr != NULL)
  454.    {  /* correct filename in case of toplevel dir */
  455.       Ptr2 = strchr(Ptr+1,'/');
  456.       if ((Ptr2 == NULL) && (Name[0] == '/'))
  457.       {
  458.          char End[256];
  459.          strcpy(End,Ptr);
  460.          *(Ptr+1) = '\0';
  461.          strcat(Name,"000000");
  462.          strcat(Name,End);
  463.       }
  464.    }
  465.  
  466.    /* try in case a file on toplevel directory or .DIR was alreadyt specified */
  467.    Result = stat(Name,info);
  468.    if (Result == 0)
  469.       return(Result);
  470.  
  471.    /* add .DIR and try again */
  472.    strcat(Name,".dir");
  473.    Result = stat(Name,info);
  474.    return(Result);
  475. }
  476.  
  477. /*** "dirent.h" ***/
  478. #include <types.h>
  479.  
  480. #ifndef    _POSIX_SOURCE
  481. #define    d_ino    d_fileno    /* compatability */
  482. #ifndef    NULL
  483. #define    NULL    0
  484. #endif
  485. #endif    /* !_POSIX_SOURCE */
  486.  
  487. typedef    struct __dirdesc {
  488. #if 0
  489.     int    dd_fd;        /* file descriptor */
  490.     long    dd_loc;        /* buf offset of entry from last readddir() */
  491.     long    dd_size;    /* amount of valid data in buffer */
  492.     long    dd_bsize;    /* amount of entries read at a time */
  493.     long    dd_off;        /* Current offset in dir (for telldir) */
  494.     char    *dd_buf;    /* directory data buffer */
  495. #endif
  496.     long     context;    /* context descriptor for LIB$FIND_FILE calls */
  497.     char    dirname[255+1];    /* keeps the directory name, including *.* */
  498.     struct dsc$descriptor_s dirname_desc;    /* descriptor of dirname */
  499. } DIR;
  500.  
  501. extern    DIR *opendir(char *dirname);
  502. extern    struct dirent *readdir(DIR *dirp);
  503. extern    int closedir(DIR *dirp);
  504. #if 0
  505. #ifndef    _POSIX_SOURCE
  506. extern    void seekdir(/* DIR *dirp, int loc */);
  507. extern    long telldir(/* DIR *dirp */);
  508. #endif    /* POSIX_SOURCE */
  509. extern    void rewinddir(/* DIR *dirp */);
  510.  
  511. #ifndef    lint
  512. #define    rewinddir(dirp)    seekdir((dirp), (long)0)
  513. #endif
  514. #endif /* not defined for VMS */
  515.  
  516. /*** #include "sys_dirent.h" ***/
  517. /*** "sys_dirent.h" ***/
  518. struct    dirent {
  519. #if 0
  520.     off_t        d_off;        /* offset of next disk dir entry */
  521. #endif
  522.     unsigned long    d_fileno;    /* file number of entry */
  523. #if 0
  524.     unsigned short    d_reclen;    /* length of this record */
  525. #endif
  526.     unsigned short    d_namlen;    /* length of string in d_name */
  527.     char        d_name[255+1];    /* name (up to MAXNAMLEN + 1) */
  528. };
  529.  
  530. #ifndef    _POSIX_SOURCE
  531. /*
  532.  * It's unlikely to change, but make sure that sizeof d_name above is
  533.  * at least MAXNAMLEN + 1 (more may be added for padding).
  534.  */
  535. #define    MAXNAMLEN    255
  536. /*
  537.  * The macro DIRSIZ(dp) gives the minimum amount of space required to represent
  538.  * a directory entry.  For any directory entry dp->d_reclen >= DIRSIZ(dp).
  539.  * Specific filesystem types may use this macro to construct the value
  540.  * for d_reclen.
  541.  */
  542. #undef    DIRSIZ
  543. #define    DIRSIZ(dp) \
  544.     (((sizeof(struct dirent) - (MAXNAMLEN+1) + ((dp)->d_namlen+1)) +3) & ~3)
  545.  
  546. #endif    /* !_POSIX_SOURCE */
  547.  
  548.  
  549. DIR *opendir(char *dirname)
  550. {
  551. static DIR dir;
  552. char *closebracket;
  553. long status;
  554. struct dsc$descriptor_s entryname_desc;
  555. struct dsc$descriptor_s dirname_desc;
  556. char DirEntry[256];
  557. char VMSentry[256];
  558. char UnixEntry[256];
  559. int index;
  560. char *dot;
  561.  
  562.    /* check if directory exists */
  563.    /* dirname can look like /disk$user/duns/www/test/multi    */
  564.    /* or like               /disk$user/duns/www/test/multi/   */
  565.    /* DirEntry should look like     disk$user:[duns.www.test]multi in both cases */
  566.    /* dir.dirname should look like  disk$user:[duns.www.test.multi] */
  567.    strcpy(UnixEntry,dirname);
  568.    if (UnixEntry[strlen(UnixEntry)-1] != '/')
  569.       strcat(UnixEntry,"/");
  570.  
  571.    strcpy(DirEntry, HTVMS_name("",UnixEntry));
  572.    strcpy(dir.dirname, DirEntry);
  573.    index = strlen(DirEntry) - 1;
  574.  
  575.    if (DirEntry[index] == ']')
  576.       DirEntry[index] = '\0';
  577.  
  578.    if ((dot = strrchr(DirEntry,'.')) == NULL)
  579.    {  /* convert disk$user:[duns] into disk$user:[000000]duns.dir */
  580.       char *openbr = strrchr(DirEntry,'[');
  581.       if (!openbr)
  582.       { /* convert disk$user: into disk$user:[000000]000000.dir */
  583.          strcpy(dir.dirname, DirEntry);
  584.          strcat(dir.dirname, "[000000]");
  585.          strcat(DirEntry,"[000000]000000.dir");
  586.       }
  587.       else
  588.       {
  589.          char End[256];
  590.          strcpy(End,openbr+1);
  591.          *(openbr+1) = '\0';
  592.          strcat(DirEntry,"000000]");
  593.          strcat(DirEntry,End);
  594.          strcat(DirEntry,".dir");
  595.       }
  596.    }
  597.    else
  598.    {
  599.       *dot = ']';   
  600.       strcat(DirEntry,".dir");
  601.    }
  602.  
  603.    dir.context = 0;
  604.    dirname_desc.dsc$w_length = strlen(DirEntry);
  605.    dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  606.    dirname_desc.dsc$b_class = DSC$K_CLASS_S;
  607.    dirname_desc.dsc$a_pointer = (char *)&(DirEntry);
  608.  
  609.    /* look for the directory */
  610.    entryname_desc.dsc$w_length = 255;
  611.    entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  612.    entryname_desc.dsc$b_class = DSC$K_CLASS_S;
  613.    entryname_desc.dsc$a_pointer = VMSentry;
  614.  
  615.    status = lib$find_file(&(dirname_desc), 
  616.                           &entryname_desc, 
  617.                           &(dir.context),
  618.                           0,0,0,0);
  619.    if (!(status & 0x01))
  620.    { /* directory not found */
  621.       return(NULL);
  622.    }
  623.  
  624. #if 0
  625.    /* now correct dirname, which looks like disk$user:[duns.www.test]multi */
  626.    /* and should look like disk$user:[duns.www.test.multi] */
  627.    closebracket = strchr(dir.dirname,']');
  628.    *closebracket = '.';
  629.    closebracket = strstr(dir.dirname,".dir");
  630.    *closebracket = '\0';
  631.    strcat(dir.dirname,"]");
  632. #endif
  633.  
  634.    if (HTVMSFileVersions)
  635.        strcat(dir.dirname,"*.*;*");
  636.    else
  637.        strcat(dir.dirname,"*.*");
  638.    dir.context = 0;
  639.    dir.dirname_desc.dsc$w_length = strlen(dir.dirname);
  640.    dir.dirname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  641.    dir.dirname_desc.dsc$b_class = DSC$K_CLASS_S;
  642.    dir.dirname_desc.dsc$a_pointer = (char *)&(dir.dirname);
  643.    return(&dir);
  644. }
  645.  
  646. struct dirent *readdir(DIR *dirp)
  647. {
  648. static struct dirent entry;
  649. long status;
  650. struct dsc$descriptor_s entryname_desc;
  651. char *space, *slash;
  652. char VMSentry[256];
  653. char *UnixEntry;
  654.  
  655.    entryname_desc.dsc$w_length = 255;
  656.    entryname_desc.dsc$b_dtype = DSC$K_DTYPE_T;
  657.    entryname_desc.dsc$b_class = DSC$K_CLASS_S;
  658.    entryname_desc.dsc$a_pointer = VMSentry;
  659.  
  660.    status = lib$find_file(&(dirp->dirname_desc), 
  661.                           &entryname_desc, 
  662.                           &(dirp->context),
  663.                           0,0,0,0);
  664.    if (status == RMS$_NMF)
  665.    { /* no more files */
  666.       return(NULL);
  667.    }
  668.    else
  669.    { /* ok */
  670.       if (!(status & 0x01)) return(0);
  671.       if (HTVMSFileVersions)
  672.           space = strchr(VMSentry,' ');
  673.       else
  674.           space = strchr(VMSentry,';');
  675.       if (space)
  676.          *space = '\0';
  677.  
  678.       /* convert to unix style... */
  679.       UnixEntry = HTVMS_wwwName(VMSentry);
  680.       slash = strrchr(UnixEntry,'/') + 1;
  681.       strcpy(entry.d_name,slash);
  682.       entry.d_namlen = strlen(entry.d_name);
  683.       entry.d_fileno = 1;
  684.       return(&entry);
  685.    }
  686. }
  687.  
  688. int closedir(DIR *dirp)
  689. {
  690. long status;
  691.  
  692.    status = lib$find_file_end(&(dirp->context));
  693.    if (!(status & 0x01)) exit(status);
  694.    dirp->context = 0;
  695.    return(0);
  696. }
  697.  
  698. #include "HTAnchor.h"
  699. #include "HTParse.h"
  700. #include "HTBTree.h"
  701. #include "HTFile.h"    /* For HTFileFormat() */
  702. #include "HTAlert.h"
  703. #define FREE(x) if (x) {free(x); x=NULL;}
  704. /*
  705. **  Hypertext object building machinery.
  706. */
  707. #include "HTML.h"
  708. #define PUTC(c) (*targetClass.put_character)(target, c)
  709. #define PUTS(s) (*targetClass.put_string)(target, s)
  710. #define START(e) (*targetClass.start_element)(target, e, 0, 0)
  711. #define END(e) (*targetClass.end_element)(target, e)
  712. #define FREE_TARGET (*targetClass._free)(target)
  713. #define ABORT_TARGET (*targetClass._free)(target)
  714. struct _HTStructured {
  715.     CONST HTStructuredClass *    isa;
  716.     /* ... */
  717. };
  718.  
  719. #define STRUCT_DIRENT struct dirent
  720.  
  721. PRIVATE char * months[12] = {
  722.     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
  723. };
  724.  
  725. typedef struct _VMSEntryInfo {
  726.     char *       filename;
  727.     char *       type;
  728.     char *       date;
  729.     unsigned int size;
  730.     BOOLEAN      display;  /* show this entry? */
  731. } VMSEntryInfo;
  732.  
  733. PRIVATE void free_VMSEntryInfo_struct_contents ARGS1(VMSEntryInfo *,entry_info)
  734. {
  735.     if(entry_info) {
  736.         if(entry_info->filename) free(entry_info->filename);
  737.         if(entry_info->type) free(entry_info->type);
  738.         if(entry_info->date) free(entry_info->date);
  739.     }
  740.    /* dont free the struct */
  741. }
  742.  
  743. #define FILE_BY_NAME 0 
  744. #define FILE_BY_TYPE 1
  745. #define FILE_BY_SIZE 2
  746. #define FILE_BY_DATE 3
  747. extern BOOLEAN HTfileSortMethod;  /* specifies the method of sorting */
  748.  
  749. PUBLIC int compare_VMSEntryInfo_structs ARGS2(VMSEntryInfo *,entry1, 
  750.                           VMSEntryInfo *,entry2)
  751. {
  752.     int status;
  753.  
  754.     switch(HTfileSortMethod)
  755.       {
  756.         case FILE_BY_SIZE:
  757.             /* both equal or both 0 */
  758.                         if(entry1->size == entry2->size)
  759.                 return(strcasecomp(entry1->filename, 
  760.                             entry2->filename));
  761.             else
  762.                 if(entry1->size > entry2->size)
  763.                 return(1);
  764.                 else
  765.                 return(-1);
  766.                         break;
  767.         case FILE_BY_TYPE:
  768.                         if(entry1->type && entry2->type) {
  769.                             status = strcasecomp(entry1->type, entry2->type);
  770.                 if(status)
  771.                 return(status);
  772.                 /* else fall to filename comparison */
  773.             }
  774.                         return (strcasecomp(entry1->filename, 
  775.                             entry2->filename));
  776.                         break;
  777.         case FILE_BY_DATE:
  778.                         if(entry1->date && entry2->date) {
  779.                                 /* We really should change the type :( */
  780.                             status = strcasecomp(entry1->date, entry2->date);
  781.                 if(status)
  782.                 return(status);
  783.                 /* else fall to filename comparison */
  784.             }
  785.                         return (strcasecomp(entry1->filename, 
  786.                             entry2->filename));
  787.                         break;
  788.         case FILE_BY_NAME:
  789.         default:
  790.                         return (strcasecomp(entry1->filename, 
  791.                             entry2->filename));
  792.       }
  793. }
  794.  
  795.  
  796. /*                                HTVMSBrowseDir()
  797. **
  798. **    This function generates a directory listing as an HTML-object
  799. **    for local file URL's.  It assumes the first two elements of
  800. **    of the path are a device followed by a directory:
  801. **
  802. **        file://localhost/device/directory[/[foo]]
  803. **
  804. **    Will not accept 000000 as a directory name.
  805. **    Will offer links to parent through the top directory, unless
  806. **    a terminal slash was included in the calling URL.
  807. **
  808. **    Returns HT_LOADED on success, HTLoadError() messages on error.
  809. **
  810. **    Developed for Lynx by Foteos Macrides (macrides@sci.wfeb.edu).
  811. */
  812. PUBLIC int HTVMSBrowseDir ARGS4(
  813.     CONST char *,        address,
  814.     HTParentAnchor *,    anchor,
  815.     HTFormat,        format_out,
  816.     HTStream *,        sink
  817. )
  818. {
  819.     HTStructured* target;
  820.     HTStructuredClass targetClass;
  821.     char *pathname = HTParse(address, "", PARSE_PATH + PARSE_PUNCTUATION);
  822.     char *tail = NULL;
  823.     char *title = NULL;
  824.     char *header = NULL;
  825.     char *parent = NULL;
  826.     char *relative = NULL;
  827.     char *cp, *cp1;
  828.     int  pathend;
  829.     DIR *dp;
  830.     struct stat file_info;
  831.     time_t NowTime;
  832.     static char ThisYear[8];
  833.     VMSEntryInfo *entry_info=0;
  834.     char string_buffer[64];
  835.     extern BOOLEAN nodotfiles;
  836.  
  837.     CTRACE(stderr,"HTVMSBrowseDir: Browsing `%s\'\n", pathname);
  838.  
  839.     /*
  840.      *  Require at least two elements (presumably a device and directory)
  841.      *  and disallow the device root (000000 directory).  Symbolic paths
  842.      *  (e.g., sys$help) should have been translated and expanded (e.g.,
  843.      *  to /sys$sysroot/syshlp) before calling this routine.
  844.      */
  845.     if (((*pathname != '/') ||
  846.          (cp=strchr(pathname+1, '/')) == NULL ||
  847.      *(cp+1) == '\0' ||
  848.      0==strncmp((cp+1), "000000", 6)) ||
  849.         (dp=opendir(pathname)) == NULL) {
  850.         FREE(pathname);
  851.         return HTLoadError(sink, 403, "Could not access directory.");
  852.     }
  853.  
  854.     /*
  855.      *  Set up the output stream.
  856.      */
  857.     _HTProgress ("Building directory listing...");
  858.     target = HTML_new(anchor, format_out, sink);
  859.     targetClass = *(target->isa);
  860.  
  861.     /*
  862.      *  Set up the offset string of the anchor reference,
  863.      *  and strings for the title and header.
  864.      */
  865.     cp = strrchr(pathname, '/');  /* find lastslash */
  866.     StrAllocCopy(tail, (cp+1)); /* take slash off the beginning */
  867.     if (*tail != '\0') {
  868.         StrAllocCopy(title, tail);
  869.     *cp = '\0';
  870.     if ((cp1=strrchr(pathname, '/')) != NULL &&
  871.         cp1 != pathname &&
  872.         strncmp((cp1+1), "000000", 6))
  873.         StrAllocCopy(parent, (cp1+1));
  874.     *cp = '/';
  875.     } else {
  876.         pathname[strlen(pathname)-1] = '\0';
  877.     cp = strrchr(pathname, '/');
  878.     StrAllocCopy(title, (cp+1));
  879.     pathname[strlen(pathname)] = '/';
  880.     }
  881.     StrAllocCopy(header, pathname);
  882.  
  883.     /*
  884.      *  Initialize path name for HTStat().
  885.      */
  886.     pathend = strlen(pathname);
  887.     if (*(pathname+pathend-1) != '/') {
  888.     StrAllocCat(pathname, "/");
  889.     pathend++;
  890.     }
  891.     
  892.     /*
  893.      *  Output the title and header.
  894.      */
  895.     START(HTML_HTML);
  896.     PUTS("\n");
  897.     START(HTML_HEAD);
  898.     PUTS("\n");
  899.     HTUnEscape(title);
  900.     START(HTML_TITLE);
  901.     PUTS(title);
  902.     PUTS(" directory");
  903.     END(HTML_TITLE);
  904.     PUTS("\n");
  905.     FREE(title);
  906.     END(HTML_HEAD);
  907.     PUTS("\n");
  908.     START(HTML_BODY);
  909.     PUTS("\n");
  910.     HTUnEscape(header);
  911.     START(HTML_H1);
  912.     PUTS(header);
  913.     END(HTML_H1);
  914.     PUTS("\n");
  915.     if (HTDirReadme == HT_DIR_README_TOP) {
  916.         FILE * fp;
  917.     if (header[strlen(header)-1] != '/')
  918.         StrAllocCat(header, "/");
  919.     StrAllocCat(header, HT_DIR_README_FILE);
  920.         if ((fp = fopen(header,  "r")) != NULL) {
  921.         START(HTML_PRE);
  922.         for(;;) {
  923.             char c = fgetc(fp);
  924.             if (c == (char)EOF) break;
  925.             switch (c) {
  926.                 case '&':
  927.             case '<':
  928.             case '>':
  929.             PUTC('&');
  930.             PUTC('#');
  931.             PUTC((char)(c / 10));
  932.             PUTC((char) (c % 10));
  933.             PUTC(';');
  934.             break;
  935.             default:
  936.             PUTC(c);
  937.             }
  938.         }
  939.         END(HTML_PRE);
  940.         fclose(fp);
  941.         } 
  942.     }
  943.     FREE(header);
  944.     if (parent) {
  945.     relative = (char*) malloc(strlen(tail) + 4);
  946.     if (relative == NULL)
  947.         outofmem(__FILE__, "HTVMSBrowseDir");
  948.     sprintf(relative, "%s/..", tail);
  949.     HTStartAnchor(target, "", relative);
  950.     PUTS("Up to ");
  951.     HTUnEscape(parent);
  952.     PUTS(parent);
  953.     END(HTML_A);
  954.     START(HTML_P);
  955.     PUTS("\n");
  956.     FREE(relative);
  957.     FREE(parent);
  958.     }
  959.  
  960.     /*
  961.      *  Set up the date comparison.
  962.      */
  963.     NowTime = time(NULL);
  964.     strcpy(ThisYear, (char *)ctime(&NowTime)+20);
  965.     ThisYear[4] = '\0';
  966.  
  967.     /*
  968.      * Now, generate the Btree and put it out to the output stream.
  969.      */
  970.     {
  971.     char dottest = 2;    /* To avoid two strcmp() each time */
  972.     STRUCT_DIRENT *dirbuf;
  973.     HTBTree *bt;
  974.  
  975.     /* Set up sort key and initialize BTree */
  976.     bt = HTBTree_new((HTComparer) compare_VMSEntryInfo_structs);
  977.  
  978.     /* Build tree */
  979.     while ((dirbuf = readdir(dp))) {
  980.         HTAtom *encoding = NULL;
  981.         HTFormat format;
  982.  
  983.         /* Skip if not used */
  984.         if (!dirbuf->d_ino)    {
  985.         continue;
  986.         }
  987.         
  988.         /* Current and parent directories are never shown in list */
  989.         if (dottest && (!strcmp(dirbuf->d_name, ".") ||
  990.                 !strcmp(dirbuf->d_name, ".."))) {
  991.         dottest--;
  992.         continue;
  993.         }
  994.  
  995.         /* Don't show the selective enabling file
  996.          * unless version numbers are included */
  997.         if (!strcasecomp(dirbuf->d_name, HT_DIR_ENABLE_FILE)) {
  998.         continue;
  999.         }
  1000.  
  1001.         /* Skip files beginning with a dot? */
  1002.         if (nodotfiles && *dirbuf->d_name == '.') {
  1003.         continue;
  1004.         }
  1005.  
  1006.         /* OK, make an lstat() and get a key ready. */
  1007.         *(pathname+pathend) = '\0';
  1008.         StrAllocCat(pathname, dirbuf->d_name);
  1009.         if (HTStat(pathname, &file_info)) {
  1010.         /* for VMS the failure here means the file is not readable...
  1011.            we however continue to browse through the directory... */
  1012.                 continue;
  1013.         }
  1014.             entry_info = (VMSEntryInfo *)malloc(sizeof(VMSEntryInfo));    
  1015.         if (entry_info == NULL)
  1016.         outofmem(__FILE__, "HTVMSBrowseDir");
  1017.         entry_info->type = 0;
  1018.         entry_info->size = 0;
  1019.         entry_info->date = 0;
  1020.         entry_info->filename = 0;
  1021.         entry_info->display = TRUE;
  1022.  
  1023.         /* Get the type */
  1024.         format = HTFileFormat(dirbuf->d_name, &encoding);
  1025.         if(!strncmp(HTAtom_name(format), "application",11)) 
  1026.           {
  1027.            cp = HTAtom_name(format) + 12;
  1028.            if(!strncmp(cp,"x-",2))
  1029.             cp+=2;
  1030.           }
  1031.         else
  1032.         cp = HTAtom_name(format);
  1033.         StrAllocCopy(entry_info->type, cp);
  1034.  
  1035.         StrAllocCopy(entry_info->filename, dirbuf->d_name);
  1036.         if ((file_info.st_mode & S_IFMT) == S_IFDIR) {
  1037.             /* strip .DIR part... */
  1038.                 char *dot;
  1039.                 dot = strstr(entry_info->filename, ".DIR");
  1040.                 if (dot)
  1041.                    *dot = '\0';
  1042.         StrAllocCopy(entry_info->type, "Directory");
  1043.         }
  1044.  
  1045.         /* Get the date */
  1046.         {
  1047.             char *t = (char *)ctime((CONST time_t *)&file_info.st_ctime);
  1048.         *(t+24) = '\0';
  1049.  
  1050.             StrAllocCopy(entry_info->date, (t+4));
  1051.         *((entry_info->date)+7) = '\0';
  1052.         if ((atoi((t+19))) < atoi(ThisYear))
  1053.             StrAllocCat(entry_info->date,  (t+19));
  1054.         else {
  1055.             StrAllocCat(entry_info->date, (t+11));
  1056.             *((entry_info->date)+12) = '\0';
  1057.         }
  1058.         }
  1059.  
  1060.         /* Get the size */
  1061.         if ((file_info.st_mode & S_IFMT) != S_IFDIR)
  1062.             entry_info->size = (unsigned int)file_info.st_size;
  1063.         else
  1064.             entry_info->size = 0;
  1065.  
  1066.         /* Now, update the BTree etc. */
  1067.         if(entry_info->display)
  1068.           {
  1069.          CTRACE(stderr,"Adding file to BTree: %s\n",
  1070.                               entry_info->filename);
  1071.              HTBTree_add(bt, (VMSEntryInfo *)entry_info); 
  1072.           }
  1073.  
  1074.     } /* End while readdir() */
  1075.  
  1076.     FREE(pathname);
  1077.     closedir(dp);
  1078.  
  1079.     START(HTML_PRE);
  1080.     /*
  1081.      * Run through the BTree printing out in order
  1082.      */
  1083.     {
  1084.         HTBTElement * ele;
  1085.         int i;
  1086.         for (ele = HTBTree_next(bt, NULL);
  1087.          ele != NULL;
  1088.          ele = HTBTree_next(bt, ele))
  1089.         {
  1090.         entry_info = (VMSEntryInfo *)HTBTree_object(ele);
  1091.  
  1092.         /* Output the date */
  1093.         if(entry_info->date) 
  1094.                {
  1095.                      PUTS(entry_info->date);
  1096.                      PUTS("  ");
  1097.                }
  1098.         else
  1099.             PUTS("     * ");
  1100.  
  1101.         /* Output the type */
  1102.         if(entry_info->type) 
  1103.           {
  1104.             for(i = 0; entry_info->type[i] != '\0' && i < 15; i++)
  1105.                 PUTC(entry_info->type[i]);
  1106.             for(; i < 17; i++)
  1107.                 PUTC(' ');
  1108.  
  1109.           }
  1110.  
  1111.         /* Output the link for the name */
  1112.         HTDirEntry(target, tail, entry_info->filename);  
  1113.         PUTS(entry_info->filename);
  1114.         END(HTML_A);
  1115.  
  1116.                 /* Output the size */
  1117.         if(entry_info->size) 
  1118.           {
  1119.                   if(entry_info->size < 1024)
  1120.                   sprintf(string_buffer,"  %d bytes",
  1121.                             entry_info->size);
  1122.               else
  1123.                   sprintf(string_buffer,"  %dKb",
  1124.                             entry_info->size/1024);
  1125.               PUTS(string_buffer);
  1126.           }
  1127.  
  1128.         PUTC('\n'); /* end of this entry */
  1129.  
  1130.         free_VMSEntryInfo_struct_contents(entry_info);
  1131.         }
  1132.     }
  1133.  
  1134.     HTBTreeAndObject_free(bt);
  1135.  
  1136.     } /* End of both BTree loops */
  1137.  
  1138.     /*
  1139.      *  Complete the output stream.
  1140.      */
  1141.     END(HTML_PRE);
  1142.     PUTS("\n");
  1143.     END(HTML_BODY);
  1144.     PUTS("\n");
  1145.     END(HTML_HTML);
  1146.     PUTS("\n");
  1147.     FREE(tail);
  1148.     FREE_TARGET;
  1149.  
  1150.     return HT_LOADED;
  1151.  
  1152. } /* End of directory reading section */
  1153.